#include "key_scan.h"

typedef enum {
    KEY_STATE_IDLE,
    KEY_STATE_JITTER,
    KEY_STATE_PRESS_DOWN,
    KEY_STATE_CP
} key_sta_t;

static key_sta_t key_sta;
static key_u8_t last_key_index = MSG_INVALID;
static key_u32_t wait_time, scan_time;
#ifdef DOUBLE_CLICK_EN
static key_u32_t double_tout = 0;                   /*!<双击超时时间*/
static key_u8_t double_cnt = 0;                     /*!<双击计数*/
static key_u8_t click_index = MSG_INVALID;          /*!<检测双击时，记录上一次按键值*/
#endif

/**
 * @brief: 按键事件列表需要定义6种按键事件
 *          1-> 按下；2-> 短按；3-> 长按；4-> 长按保持；5-> 长按放手；6-> 双击
 *         code 关键字，需要根据不同的编译器进行改变，目的就是为了将此数组存放在FLASH中，减少RAM使用量
 */
static const key_msg_t KeyEvent[][6] =
{
    /*key press       key short press           key longpress           key hold              key longpress release        key double click */
    /*  1                   2                        3                      4                           5                          6        */
    /** add your code below */
    {MSG_K1_PRESS,    MSG_K1_SHORT_PRESS,       MSG_K1_LONGPRESS,       MSG_K1_LONGPRESS_HD,  MSG_K1_LONGPRESS_RE,          MSG_K1_DOUBLE_CLICK},
    {MSG_K2_PRESS,    MSG_K2_SHORT_PRESS,       MSG_K2_LONGPRESS,       MSG_K2_LONGPRESS_HD,  MSG_K2_LONGPRESS_RE,          MSG_K2_DOUBLE_CLICK},
    {MSG_K3_PRESS,    MSG_K3_SHORT_PRESS,       MSG_K3_LONGPRESS,       MSG_K3_LONGPRESS_HD,  MSG_K3_LONGPRESS_RE,          MSG_K3_DOUBLE_CLICK},
    {MSG_K4_PRESS,    MSG_K4_SHORT_PRESS,       MSG_K4_LONGPRESS,       MSG_K4_LONGPRESS_HD,  MSG_K4_LONGPRESS_RE,          MSG_K4_DOUBLE_CLICK},
    {MSG_K5_PRESS,    MSG_K5_SHORT_PRESS,       MSG_K5_LONGPRESS,       MSG_K5_LONGPRESS_HD,  MSG_K5_LONGPRESS_RE,          MSG_K5_DOUBLE_CLICK},
	{MSG_K6_PRESS,    MSG_K6_SHORT_PRESS,       MSG_K6_LONGPRESS,       MSG_K6_LONGPRESS_HD,  MSG_K6_LONGPRESS_RE,          MSG_K6_DOUBLE_CLICK},
	{MSG_K7_PRESS,    MSG_K7_SHORT_PRESS,       MSG_K7_LONGPRESS,       MSG_K7_LONGPRESS_HD,  MSG_K7_LONGPRESS_RE,          MSG_K7_DOUBLE_CLICK},
	{MSG_K8_PRESS,    MSG_K8_SHORT_PRESS,       MSG_K8_LONGPRESS,       MSG_K8_LONGPRESS_HD,  MSG_K8_LONGPRESS_RE,          MSG_K8_DOUBLE_CLICK},
	{MSG_K9_PRESS,    MSG_K9_SHORT_PRESS,       MSG_K9_LONGPRESS,       MSG_K9_LONGPRESS_HD,  MSG_K9_LONGPRESS_RE,          MSG_K9_DOUBLE_CLICK},
	{MSG_K10_PRESS,   MSG_K10_SHORT_PRESS,      MSG_K10_LONGPRESS,      MSG_K10_LONGPRESS_HD, MSG_K10_LONGPRESS_RE,         MSG_K10_DOUBLE_CLICK},
	{MSG_K11_PRESS,   MSG_K11_SHORT_PRESS,      MSG_K11_LONGPRESS,      MSG_K11_LONGPRESS_HD, MSG_K11_LONGPRESS_RE,         MSG_K11_DOUBLE_CLICK},
};

extern void Key_Init_Port(void);
extern key_u8_t Get_KeyIndex_Port(void);
extern key_u32_t Get_Clk_Port(void);

void Key_Init(void)
{
    Key_Init_Port();
    key_sta = KEY_STATE_IDLE;
    wait_time = scan_time = Get_Clk_Port();
}

key_msg_t Key_Scan(void)
{
	key_u8_t key_index;

    if (KEY_SCAN_TIME > (key_u32_t)(Get_Clk_Port() - scan_time)) {
        return MSG_INVALID;
    } else {
        scan_time = Get_Clk_Port();
    }

	key_index = Get_KeyIndex_Port();

#ifdef DOUBLE_CLICK_EN
    if (double_cnt) {
        if (DOUBLE_CLICK_TOUT < (key_u32_t)(Get_Clk_Port() - double_tout)) {
            double_cnt = 0;
            return KeyEvent[click_index-1][1];
        }
    }
    if (MSG_INVALID == key_index) {
        double_cnt = 0;
        click_index = MSG_INVALID;
    }
#endif

	switch (key_sta) {
		case KEY_STATE_IDLE:{
            if (!key_index) {
                return MSG_KEY_NONE;
            }

            last_key_index = key_index;
            wait_time = Get_Clk_Port();
            key_sta = KEY_STATE_JITTER;
            break;
		}

		case KEY_STATE_JITTER: {
            if (last_key_index != key_index) {
                key_sta = KEY_STATE_IDLE;
            } else if (KEY_JITTER_TIME <= (key_u32_t)(Get_Clk_Port() - wait_time)) {
                wait_time = Get_Clk_Port();
                key_sta = KEY_STATE_PRESS_DOWN;
                #ifdef DOUBLE_CLICK_EN
                    if (double_cnt) {
                        if (click_index != last_key_index) {
                            double_cnt = 0;
                            click_index = MSG_INVALID;
                        }
                    }
                #endif
                // if (last_key_index == 2)
                //     LED3 = 0;
                return KeyEvent[last_key_index-1][0];
            }
            break;
		}

		case KEY_STATE_PRESS_DOWN: {
            if (last_key_index != key_index) {
                key_sta = KEY_STATE_IDLE;
                #ifdef DOUBLE_CLICK_EN
                    if (DOUBLE_CNT <= ++double_cnt) {
                        if (click_index == last_key_index) {
                            double_cnt = 0;
                            click_index = MSG_INVALID;
                            return KeyEvent[last_key_index-1][5];
                        } else {
                            double_cnt = 1;
                            click_index = last_key_index;
                            double_tout = Get_Clk_Port();
                            return KeyEvent[last_key_index-1][1];
                        }
                    } else {
                        click_index = last_key_index;
                        double_tout = Get_Clk_Port();
                    }
                #else
                    return KeyEvent[last_key_index-1][1];
                #endif
            } else if (KEY_CP_TIME <= (key_u32_t)(Get_Clk_Port() - wait_time)) {
                wait_time = Get_Clk_Port();
                key_sta = KEY_STATE_CP;
                return KeyEvent[last_key_index-1][2];
            }
            break;
		}

		case KEY_STATE_CP: {
            if (last_key_index != key_index) {
                key_sta = KEY_STATE_IDLE;
                return KeyEvent[last_key_index-1][4];
            } else if (KEY_CPH_TIME <= (key_u32_t)(Get_Clk_Port() - wait_time)) {
                wait_time = Get_Clk_Port();
                return KeyEvent[last_key_index-1][3];
            }
            break;
		}

		default: {
            key_sta = KEY_STATE_IDLE;
            break;
		}
	}
	return MSG_INVALID;
}

